#pragma once

#include <winsock2.h>
#include <string>

class IocpPacket;
class IocpRecv;
class IocpSend;
class IocpAccept;
class NetworkModule;

class SSession
{
public:
	enum E_STATE
	{
		eNOT_READY,
		eREADY,
	};

	enum E_IOCP_TYPE
	{        
		eTYPE_ACCEPT=0,
		eTYPE_RECV=1,
		eTYPE_SEND=2,
		eTYPE_DISCONNECT=3,
		eTYPE_CONNECT
	};

	struct ST_IOCP_DATA : public OVERLAPPED
	{
		int	_type;
		DWORD _size;
		DWORD _flags;
		SSession* _pSession;
		ST_IOCP_DATA():_pSession(nullptr), _flags(0), _type(eTYPE_CONNECT), _size(0)
		{}
	};

#define ACCEPTED_ADDR_SIZE_ ( (sizeof( SOCKADDR_IN ) + 16 ) * 2)
	struct ST_IOCP_ACCEPT : public OVERLAPPED
	{
		int _type;
		SOCKET _socket;
		SSession* _pSession;
		BYTE _pAcceptBuf[ACCEPTED_ADDR_SIZE_];
		
		ST_IOCP_ACCEPT()
			:_type(eTYPE_ACCEPT), _socket(NULL), _pSession(nullptr)
		{
		}
	};
	
public:
	SSession(NetworkModule* pNetworkModule);
	virtual ~SSession();
	
	void Create();
	void Destroy();

	bool Accept(const TCHAR* pIP, const int& port);
	void Connect(const std::string& ip, const int& port);		
	void Send(unsigned long type, BYTE* pPacket, const size_t& size);
	bool Disconnect();
	bool DisconnectForce();

	bool AssociateIOCPKey();
		
	bool PostRecv();
	bool PostSend();

	//after completion 
	void IODisconnect();
	void IOWrite(const DWORD& recvSize);
	void IORead(const DWORD& recvSize);

	//seperate each.
	int ProcessRecv(BYTE* pPacket, int recvSize);

	virtual void OnAccept();
	virtual void OnConnect(const bool& result);
	virtual void OnSend(size_t size);
	virtual void OnRecv(int type, BYTE* pPacket, int size);
	virtual void OnDisconnect();

	ST_IOCP_DATA* GetRecvIocpData();
	ST_IOCP_DATA* GetSendIocpData();        
	ST_IOCP_DATA* GetDisIocpData();
	ST_IOCP_ACCEPT* GetAccpIocpData();

	void SetSocket(SOCKET  socket){m_socket=socket;}
	SOCKET GetSocket() const { return m_socket; }
	void SetID(int id) {m_ID=id;}
	int GetID() const { return m_ID; }

	void SetState(const E_STATE& state) {m_state=state;}
	E_STATE GetState() {return m_state;}
	E_STATE m_state;


	// todo : set 
	std::wstring m_ip;
	int m_port;	
	SOCKADDR_IN	 m_addr;        

	int m_ID;	
	SOCKET m_socket;

	ST_IOCP_DATA m_sendIoData;
	ST_IOCP_DATA m_recvIoData;
	ST_IOCP_DATA m_disloData;
	ST_IOCP_ACCEPT m_acceptloData;

	IocpRecv* m_pIocpRecv;
	IocpSend* m_pIocpSend;
	IocpAccept* m_pIocpAccept;
	SSession* m_pAcceptSession;
	NetworkModule* m_pNetworkModule;
};
